<template>
  <Modal
    v-model="showEditDebugTestcaseModal"
    title="编辑 | 调试用例"
    :mask-closable="false"
    :closable="false"
    fullscreen
    @on-cancel="handleEditDebugTestcaseCancel"
  >
    <Form
      label-position="right"
      :label-width="135"
      ref="testcaseForm"
      :model="testcaseForm"
      :rules="testcaseValidate"
    >
      <Tabs name="testcase-debug-tabs" v-model="tabs" :animated="true">
        <TabPane
          label="基础信息"
          tab="testcase-debug-tabs"
          name="debugTabPaneBasicInfo"
        >
          <FormItem label="运行环境(调试专用)">
            <Select
              placeholder="请选择运行环境…"
              filterable
              v-model="environment"
            >
              <Option
                v-for="item in environments"
                :key="item.id"
                :value="item.id"
                :label="item.name"
              >
                <span>{{ item.name }}</span>
                <span style="float: right; color: #ccc">{{
                  item.base_url
                }}</span>
              </Option>
            </Select>
          </FormItem>
          <FormItem label="用例名称" prop="name">
            <Input clearable v-model="testcaseForm.name" />
          </FormItem>
          <FormItem label="关联接口" prop="api">
            <div style="display: flex; align-items: center">
              <Select filterable transfer v-model="testcaseForm.api">
                <Option
                  v-for="item in apis"
                  :key="item.id"
                  :value="item.id"
                  :label="item.name"
                >
                  <span>{{ item.name }}</span>
                  <span style="float: right; color: #ccc"
                    >{{ item.url }} — {{ item.method }}</span
                  >
                </Option>
              </Select>
              <Button
                type="primary"
                ghost
                style="color: #2d8cf0; margin-left: 10px"
                @click="synApiData"
                >同步接口</Button
              >
            </div>
          </FormItem>
          <FormItem label="请求URL" prop="url">
            <Input v-model="testcaseForm.url" />
          </FormItem>
          <FormItem label="备注">
            <Input
              type="textarea"
              clearable
              v-model="testcaseForm.remark"
              :rows="10"
            />
          </FormItem>
        </TabPane>
        <TabPane label="Headers参数" tab="testcase-debug-tabs">
          <div class="radio-group">
            <span class="radio-group-item">Content-Type</span>
            <RadioGroup
              v-model="contentType"
              @on-change="changeHeaderRadio('Content-Type', contentType)"
            >
              <Radio label="无" class="radio-group-item"></Radio>
              <Radio label="application/json" class="radio-group-item"></Radio>
              <Radio
                label="application/x-www-form-urlencoded"
                class="radio-group-item"
              ></Radio>
            </RadioGroup>
          </div>
          <div class="radio-group">
            <span class="radio-group-item">Authorization</span>
            <RadioGroup
              v-model="authorization"
              @on-change="changeHeaderRadio('Authorization', authorization)"
            >
              <Radio label="无" class="radio-group-item"></Radio>
              <Radio label="Bearer Token" class="radio-group-item"></Radio>
            </RadioGroup>
          </div>
          <JsonEditor
            v-model="testcaseForm.headers"
            jsonEditorId="debugTestcaseHeaders"
            style="height: 700px"
          ></JsonEditor>
        </TabPane>
        <TabPane :label="bodyTabPaneLabel" tab="testcase-debug-tabs">
          <FormItem label="参数类型" :label-width="80" prop="request_data_type">
            <RadioGroup v-model="testcaseForm.request_data_type">
              <Radio label="Json"></Radio>
              <Radio label="Form Data"></Radio>
            </RadioGroup>
          </FormItem>
          <JsonEditor
            v-model="testcaseForm.request_data"
            jsonEditorId="debugTestcaseRequestData"
            style="height: 700px"
          ></JsonEditor>
        </TabPane>
        <TabPane label="期望结果" tab="testcase-debug-tabs">
          <div class="button-group">
            <Button
              type="primary"
              class="button-group-item"
              @click="showExpectResultEditDrawer"
              >用例断言 | 提取变量</Button
            >
          </div>
          <JsonEditor
            v-model="testcaseForm.expect_result"
            jsonEditorId="debugTestcaseExpectResult"
            style="height: 720px"
          ></JsonEditor>
        </TabPane>
        <TabPane label="用例调试" tab="testcase-debug-tabs" name="debugTabPane">
          <Collapse value="debugResult">
            <Panel name="cookies">
              <span>COOKIES（设置有效cookies信息，实现免登录调试）</span>
              <JsonEditor
                slot="content"
                v-model="testcaseForm.cookies"
                jsonEditorId="debugTestcaseCookies"
                style="height: 300px"
              ></JsonEditor>
            </Panel>
            <Panel name="debugResult">
              <span>用例调试结果</span>
              <div slot="content">
                <Row :gutter="10">
                  <Col span="6">
                    <FormItem label="执行时间" :label-width="100">
                      <DatePicker
                        type="date"
                        readonly
                        :value="testcaseResult.execute_time"
                        format="yyyy-MM-dd HH:mm:ss"
                        style="width: 100%"
                      />
                    </FormItem>
                  </Col>
                  <Col span="6">
                    <FormItem label="响应时长(ms)" :label-width="100">
                      <Input readonly :value="testcaseResult.elapsed_ms" />
                    </FormItem>
                  </Col>
                  <Col span="6">
                    <FormItem label="响应状态码" :label-width="100">
                      <Input
                        readonly
                        :value="testcaseResult.actual_status_code"
                      />
                    </FormItem>
                  </Col>
                  <Col span="6">
                    <FormItem label="调试结果" :label-width="100">
                      <Input
                        readonly
                        :value="
                          testcaseResult.status === 'PASS'
                            ? '通过'
                            : testcaseResult.status === 'FAIL'
                            ? '失败'
                            : ''
                        "
                        :class="
                          testcaseResult.status === 'PASS'
                            ? 'input-call-pass'
                            : 'input-call-fail'
                        "
                      />
                    </FormItem>
                  </Col>
                </Row>
                <Row :gutter="10">
                  <Col span="18">
                    <FormItem label="请求URL" :label-width="100">
                      <Input readonly :value="testcaseResult.url" />
                    </FormItem>
                  </Col>
                  <Col span="6">
                    <FormItem label="请求方法" :label-width="100">
                      <Input readonly :value="testcaseResult.method" />
                    </FormItem>
                  </Col>
                </Row>
                <Tabs name="testcase-debug-result-tabs" :animated="true">
                  <TabPane label="Headers参数" tab="testcase-debug-result-tabs">
                    <JsonEditor
                      :value="testcaseResult.headers"
                      jsonEditorId="debugTestcaseResultHeaders"
                      style="height: 720px"
                    ></JsonEditor>
                  </TabPane>
                  <TabPane
                    :label="debugBodyTabPaneLabel"
                    tab="testcase-debug-result-tabs"
                  >
                    <JsonEditor
                      :value="testcaseResult.request_data"
                      jsonEditorId="debugTestcaseResultRequestData"
                      style="height: 720px"
                    ></JsonEditor>
                  </TabPane>
                  <TabPane label="响应结果" tab="testcase-debug-result-tabs">
                    <JsonEditor
                      :value="testcaseResult.actual_response_data"
                      jsonEditorId="debugTestcaseResultActualResponseData"
                      style="height: 720px"
                    ></JsonEditor>
                  </TabPane>
                  <TabPane
                    label="输出变量结果"
                    tab="testcase-debug-result-tabs"
                  >
                    <JsonEditor
                      :value="testcaseResult.output_result"
                      jsonEditorId="debugTestcaseResultOutputResult"
                      style="height: 720px"
                    ></JsonEditor>
                  </TabPane>
                  <TabPane
                    label="调试失败原因"
                    tab="testcase-debug-result-tabs"
                  >
                    <JsonEditor
                      :value="testcaseResult.failure_reason"
                      jsonEditorId="debugTestcaseResultFailureReason"
                      style="height: 720px"
                    ></JsonEditor>
                  </TabPane>
                </Tabs>
              </div>
            </Panel>
          </Collapse>
        </TabPane>
      </Tabs>
    </Form>
    <div slot="footer">
      <Button type="default" @click="handleEditDebugTestcaseCancel"
        >取消</Button
      >
      <Button type="primary" @click="handleEditTestcaseSubmit('testcaseForm')"
        >更新用例</Button
      >
      <template>
        <Button type="default" @click="handleDebugTestcaseSubmit"
          >调试用例</Button
        >
        <Button
          :disabled="!isDebugged"
          type="primary"
          @click="handleSaveTestcaseResultSubmit('testcaseResult')"
          >保存用例结果</Button
        >
      </template>
    </div>
    <ExpectResultEdit
      :showDrawer.sync="showDrawer"
      :expectResult.sync="tempExpectResult"
      @updateExpectResult="updateExpectResult"
    ></ExpectResultEdit>
  </Modal>
</template>

<script>
import { createTestcaseResult } from "@/api/HttpAutoTestService/testcase-result";
import { getProjectById } from "@/api/HttpAutoTestService/project";
import { getApiNames } from "@/api/HttpAutoTestService/api";
import {
  updateTestcase,
  debugTestcase,
} from "@/api/HttpAutoTestService/testcase";
import JsonEditor from "_c/json-editor";
import ExpectResultEdit from "./expect-result-edit";

export default {
  name: "testcase-edit-debug",
  components: {
    JsonEditor,
    ExpectResultEdit,
  },
  props: {
    editDebugTestcase: {
      type: Boolean,
      default: false,
    },
    testcase: {
      type: Object,
      default: () => {
        return {};
      },
    },
  },
  computed: {
    showEditDebugTestcaseModal: {
      get() {
        return this.editDebugTestcase;
      },
      set(val) {
        this.$emit("update:editDebugTestcase", val);
        this.$emit("update:testcase", {});
      },
    },
    bodyTabPaneLabel() {
      return `Body参数（${this.testcaseForm.request_data_type})`;
    },
    debugBodyTabPaneLabel() {
      return `Body参数 (${this.testcaseResult.request_data_type})`;
    },
  },
  watch: {
    testcase(val) {
      if (this.showEditDebugTestcaseModal) {
        this.testcaseForm = { ...val };
        delete this.testcaseForm["project"];
        this.testcaseForm["cookies"] = {};
        let projectId = val.project;
        getProjectById(projectId)
          .then((res) => {
            let project = res.data;
            this.environments = project.environments;
            let project_default_environment = project.default_environment.id;
            // 如果运行环境为空时，指定项目默认环境
            if (!this.environment) {
              this.environment = project_default_environment;
            }
          })
          .catch((err) => {
            this.$Modal.error({
              title: "系统异常，请联系管理员……",
              content: JSON.stringify(err),
              closable: true,
            });
          });

        getApiNames({ project: projectId, detail: true })
          .then((res) => {
            this.apis = res.data;
            try {
              this.apis.forEach((item) => {
                if (item.id === this.testcaseForm.api) {
                  this.parameter_desc = item.parameter_desc;
                  this.environment = item.environment;
                  throw Error("终止循环");
                }
              });
            } catch (err) {}
          })
          .catch((err) => {
            this.$Modal.error({
              title: "系统异常，请联系管理员……",
              content: JSON.stringify(err),
              closable: true,
            });
          });
      }
    },
  },
  data() {
    return {
      showDrawer: false,
      isDebugged: false,
      tabs: "",
      environment: "",
      environments: [],
      apis: [],
      testcaseForm: {
        id: "",
        name: "",
        api: "",
        url: "",
        headers: {},
        request_data_type: "Json",
        request_params: "",
        request_data: {},
        expect_result: {},
        cookies: {},
        remark: "",
      },
      testcaseValidate: {
        name: [{ required: true, message: "请输入用例名称", trigger: "blur" }],
        api: [{ required: true, message: "请选择关联接口", trigger: "change" }],
        url: [{ required: true, message: "请输入请求URL", trigger: "blur" }],
        request_data_type: [
          { required: true, message: "请选择参数类型", trigger: "change" },
        ],
      },
      testcaseResult: {
        url: "",
        method: "",
        headers: {},
        request_data_type: "Json",
        request_data: {},
        expect_result: {},
        actual_status_code: "",
        actual_response_data: {},
        execute_time: "",
        elapsed_ms: "",
        status: "",
        output_result: {},
      },
      contentType: "application/json",
      authorization: "无",
      tempExpectResult: {},
    };
  },
  methods: {
    handleEditDebugTestcaseCancel() {
      this.showEditDebugTestcaseModal = false;
      this.tabs = "debugTabPaneBasicInfo";
      this.environment = "";
      this.environments = [];
      this.testcaseForm = {
        id: "",
        name: "",
        api: "",
        url: "",
        headers: {},
        request_data_type: "Json",
        request_params: "",
        request_data: {},
        expect_result: {},
        cookies: {},
        remark: "",
      };
      this.testcaseResult = {
        url: "",
        method: "",
        headers: {},
        request_data_type: "",
        request_data: {},
        actual_status_code: "",
        actual_response_data: {},
        execute_time: "",
        elapsed_ms: "",
        status: "",
        output_result: {},
      };
      this.$emit("initTestcaseTable");
      this.$refs["testcaseForm"].resetFields();
    },
    handleEditTestcaseSubmit(name) {
      this.$refs[name].validate((valid) => {
        if (valid) {
          let testcaseForm = { ...this.testcaseForm };
          testcaseForm.url = testcaseForm.url.trim();
          // url以/开始
          let index1 = testcaseForm.url.indexOf("/");
          if (index1 === 0) {
            let tempUrl = testcaseForm.url;
            testcaseForm.url = tempUrl.slice(index1 + 1);
          }
          // url中包含?,?之后的参数代表请求参数
          let index2 = testcaseForm.url.indexOf("?");
          if (index2 !== -1) {
            let tempUrl = testcaseForm.url;
            testcaseForm.url = tempUrl.slice(0, index2);
            testcaseForm.request_params = tempUrl.slice(index2 + 1);
          }

          delete testcaseForm.cookies;
          if (testcaseForm.headers === "") {
            testcaseForm.headers = {};
          }

          if (testcaseForm.request_data === "") {
            testcaseForm.request_data = {};
          }

          if (testcaseForm.expect_result === "") {
            testcaseForm.expect_result = {};
          }

          updateTestcase(testcaseForm)
            .then((res) => {
              if (res.status === 200) {
                this.$Message.info("修改成功");
                this.handleEditDebugTestcaseCancel();
              } else {
                this.$Message.error("修改失败");
              }
            })
            .catch((err) => {
              this.$Modal.error({
                title: "系统异常，请联系管理员……",
                content: JSON.stringify(err),
                closable: true,
              });
            });
        }
      });
    },
    handleDebugTestcaseSubmit() {
      if (this.environment == "" || this.environment == undefined) {
        this.$Message.warning("请选择运行环境…");
        return;
      }
      let testcase = { ...this.testcaseForm };
      testcase.url = testcase.url.trim();
      // url以/开始
      let index1 = testcase.url.indexOf("/");
      if (index1 === 0) {
        let tempUrl = testcase.url;
        testcase.url = tempUrl.slice(index1 + 1);
      }
      // url中包含?,?之后的参数代表请求参数
      let index2 = testcase.url.indexOf("?");
      if (index2 !== -1) {
        let tempUrl = testcase.url;
        testcase.url = tempUrl.slice(0, index2);
        testcase.request_params = tempUrl.slice(index2 + 1);
      }

      let data = {
        environment: this.environment,
        testcase: testcase,
      };
      this.tabs = "debugTabPane";
      debugTestcase(data).then((res) => {
        this.isDebugged = true;
        let data = res.data;
        this.testcaseResult = { ...data };
        this.testcaseResult.request_data_type =
          this.testcaseForm.request_data_type;
      });
    },
    handleSaveTestcaseResultSubmit() {
      createTestcaseResult(this.testcaseResult)
        .then((res) => {
          if (res.status === 201) {
            this.$Message.info("保存成功");
          } else {
            this.$Message.error("保存失败");
          }
        })
        .catch((err) => {
          this.$Modal.error({
            title: "系统异常，请联系管理员……",
            content: JSON.stringify(err),
            closable: true,
          });
        });
    },

    synApiData() {
      if (this.apis.length > 0) {
        let config = {
          width: 520,
          title: "提示：",
          content: "用例的 请求URL、Headers参数、参数类型、Body参数 都将被更新",
          onOk: () => {
            if (this.testcaseForm.api) {
              let api = this.apis.filter(
                (item) => item.id === this.testcaseForm.api
              );
              if (api.length > 0) {
                this.testcaseForm.url = api[0].url;
                let request_params = api[0].request_params;
                if (request_params) {
                  this.testcaseForm.url += "?" + request_params;
                }
                this.testcaseForm.headers = api[0].headers;
                this.testcaseForm.request_data = api[0].request_data;
                this.testcaseForm.request_data_type = api[0].request_data_type;
              }
            }
          },
        };
        this.$Modal.confirm(config);
      } else {
        this.$Message.info("关联接口加载中，请稍候……");
      }
    },
    // 更改请求头的Content-Type、Authorization内容
    changeHeaderRadio(property, value) {
      let headers = { ...this.testcaseForm.headers };
      if (value === "无") {
        delete headers[property];
      } else {
        if (property === "Content-Type") {
          headers["Content-Type"] = this.contentType;
        } else if (property === "Authorization") {
          headers["Authorization"] = this.authorization;
        }
      }
      this.testcaseForm.headers = headers;
    },
    showExpectResultEditDrawer() {
      this.tempExpectResult = this.testcaseForm.expect_result;
      this.showDrawer = true;
    },
    updateExpectResult(expectResult) {
      this.testcaseForm.expect_result = { ...expectResult };
    },
  },
};
</script>

<style scoped lang="less">
.input-call-fail :nth-last-child(1) {
  color: #ed4014 !important;
}

.input-call-pass :nth-last-child(1) {
  color: #19be6b !important;
}

span {
  font-size: 14px;
  font-weight: bold;
  color: #464c5b;
}

.ivu-form-item {
  width: 100%;
}

.radio-group {
  display: flex;
  align-items: center;
  .radio-group-item {
    margin: 0 20px 20px 0;
  }
}

.button-group {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  .button-group-item {
    margin: 0 0 10px 10px;
  }
}
</style>
